package com.nokia.bpmn.provider.rest;

import com.fasterxml.jackson.core.type.TypeReference;
import com.seed.bpmn.engine.IBPMNRuntimeService;
import com.seed.bpmn.engine.common.constants.BpmnConstants;
import com.seed.bpmn.engine.common.util.ResultData;
import com.seed.bpmn.engine.dto.*;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>流程流转时相关服务接口</p>
 *
 * @author cscz89@126.com
 */
@Component("bpmnRuntimeService")
public class BpmnRuntimeServiceImpl extends BaseService implements IBPMNRuntimeService {

    private static String BASE_RUNTIME_URL = BASE_URL + "/runtime";

    @Override
    public ProcessInstanceStartDTO start(String processDefinitionId, String businessKey,
                                         String userId, Map<String, Object> variables,
                                         boolean autoDraft) throws Exception {
        String url = BASE_RUNTIME_URL + "/process-instance/start";
        LOGGER.info("流程启动:processDefinitionId={},businessKey={},userId={},variables={},autoDraft={}",
            processDefinitionId, businessKey, userId, variables, autoDraft);

        return post(new TypeReference<ResultData<ProcessInstanceStartDTO>>() {
        }, new ArrayList<Param>() {
            {
                add(new Param("processDefinitionId", processDefinitionId));
                add(new Param("businessKey", businessKey));
                add(new Param("userId", userId));
                add(new Param("flows", variables.get("flows")));
                add(new Param(BpmnConstants.ATTRIBUTE_TASK_SUGGESTION, variables.get(BpmnConstants.ATTRIBUTE_TASK_SUGGESTION)));
                add(new Param("autoDraft", autoDraft));
                add(new Param(BpmnConstants.ATTRIBUTE_TASK_USER_CANDIDATEUSERS, variables.get(BpmnConstants.ATTRIBUTE_TASK_USER_CANDIDATEUSERS)));
            }
        }, url, null);
    }

    @Override
    public List<TaskEntityDTO> complete(String taskId, String userId, List<String> candidates, Map<String, Boolean> flows, String suggestion) throws Exception {
        return null;
    }

    @Override
    public List<TaskEntityDTO> complete(String taskId, String userId, Map<String, Object> variables, boolean localScope) throws Exception {
        String url = BASE_RUNTIME_URL + "/task/complete";
        LOGGER.info("流程任务处理方法:taskId={},userId={},variables={},localScope={}", taskId, userId,
            variables, localScope);

        return post(new TypeReference<ResultData<List<TaskEntityDTO>>>() {
        }, new ArrayList<Param>() {
            {
                add(new Param("taskId", taskId));
                add(new Param("userId", userId));
                add(new Param(BpmnConstants.ATTRIBUTE_TASK_SUGGESTION, variables.get(BpmnConstants.ATTRIBUTE_TASK_SUGGESTION)));
                add(new Param(BpmnConstants.ATTRIBUTE_TASK_USER_CANDIDATEUSERS, variables.get(BpmnConstants.ATTRIBUTE_TASK_USER_CANDIDATEUSERS)));
                add(new Param("flows", variables.get("flows")));
            }
        }, url, null);
    }

    @Override
    public boolean sign(String taskId, String userId, boolean sign) throws Exception {
        String url = BASE_RUNTIME_URL + "/task/sign";
        url += "?taskId=" + taskId + "&userId=" + userId + "&sign=" + sign;
        LOGGER.info("签收任务:taskId={},userId={},sign={}", taskId, userId, sign);
        return get(new TypeReference<ResultData<Boolean>>() {}, url);
    }

    @Override
    public List<TaskDTO> findTaskByProcessInstanceId(String processInstanceId) throws Exception {

        String url = BASE_RUNTIME_URL + "/task/process-instance-id/{0}";
        LOGGER.info("查询流程实例当前所有待办任务（不包括传阅任务）:id={}", processInstanceId);
        return get(new TypeReference<ResultData<List<TaskDTO>>>() {}, url, processInstanceId);
    }

    @Override
    public List<TaskDTO> findTaskByProcessInstanceId(String processInstanceId,
                                                     String userId) throws Exception {
        String url = BASE_RUNTIME_URL + "/task/process-instance/{0}/user/{1}";
        LOGGER.info("通过流程实例id与当前登录人查询运行任务时的任务:processInstanceId={},userId={}", processInstanceId,
            userId);
        return get(new TypeReference<ResultData<List<TaskDTO>>>() {}, url, processInstanceId, userId);
    }

    @Override
    public CommentDTO addComment(String taskId, String userId, String processInstanceId,
                                 String suggestion) throws Exception {

        String url = BASE_RUNTIME_URL + "/comment/add";
        LOGGER.info("流转意见保存方法:taskId={},userId={},processInstanceId={},suggestion={}", taskId,
            userId, processInstanceId, suggestion);

        return post(new TypeReference<ResultData<CommentDTO>>() {
        }, new ArrayList<Param>() {
            {
                add(new Param("taskId", taskId));
                add(new Param("userId", userId));
                add(new Param("processInstanceId", processInstanceId));
                add(new Param("suggestion", suggestion));
            }
        }, url, null);
    }

    @Override
    public ScheduleDTO scheduleProcess(String processInstanceId, String nodeId, List<String> candidates, String reason) throws Exception {
        String url = BASE_RUNTIME_URL + "/process/schedule";
        LOGGER.info(
                "流程调度方法:processInstanceId={},nodeId={},candidates={},suggestion={}",
                processInstanceId,nodeId, candidates, reason);

        return post(new TypeReference<ResultData<ScheduleDTO>>() {
        }, new ArrayList<Param>() {
            {
                add(new Param("processInstanceId", processInstanceId));
                add(new Param("nodeId", nodeId));
                add(new Param(BpmnConstants.ATTRIBUTE_TASK_USER_CANDIDATEUSERS, candidates));
                add(new Param("reason", reason));
            }
        }, url, null);
    }

    @Override
    public boolean deleteProcessByInstanceId(String processInstanceId, String reason) {
        String url = BASE_RUNTIME_URL + "/process/delete/{0}/{1}";
        LOGGER.info("通过流程实例Id删除流程实例:processInstanceId={}, reason={}",processInstanceId, reason);
        return post(new TypeReference<ResultData<Boolean>>() {},new ArrayList<>(), url, processInstanceId, reason);
    }
}
